import pygame

from settings import *
from support import import_folder
import random
from enum import Enum, auto

class MonsterState(Enum):
    """怪物状态枚举"""
    CHASE = auto()     # 追击状态
    ATTACK = auto()    # 攻击状态
    DYING = auto()     # 死亡状态

class BaseMonster(pygame.sprite.Sprite):
    """基础怪物类"""
    def __init__(self, pos, groups, player):
        super().__init__(groups)
        
        # 基础引用
        self.player = player
        self.level = groups[0]
        
        # 基础属性（由子类设置具体值）
        self.health = None
        self.max_health = None
        self.attack_damage = None
        self.attack_range = None
        self.speed = None
        self.attack_frame_window = None
        self.drops_experience = False  # 是否掉落经验值
        self.score_value = 0  # 添加分数属性
        
        # 状态相关
        self.current_state = MonsterState.CHASE  # 初始为追击状态
        self.state_timer = 0
        self.state_cooldowns = {
            MonsterState.ATTACK: 1.0,  # 攻击��却时间
        }
        
        # 攻击相关
        self.can_deal_damage = False
        self.damage_dealt = False
        
        # 调试标志
        self.debug = False
        
        # 动画相关
        self.status = 'down'  # 初始朝向
        self.frame_index = 0
        self.z = LAYERS['main']
        
        # 位置和方向
        self.direction = pygame.math.Vector2()
        self.pos = pygame.math.Vector2(pos)

        self.import_assets()
        
        if not self.animations:
            raise ValueError("No animations loaded")
        if self.status not in self.animations:
            raise ValueError(f"Invalid status: {self.status}")
        if not self.animations[self.status]:
            raise ValueError(f"No frames found for status: {self.status}")
            
        self.image = self.animations[self.status][int(self.frame_index)]
        self.rect = self.image.get_rect(center=pos)
        self.hitbox = self.rect.copy().inflate((-40, -40))
        
        self.hp_bar_offset = pygame.math.Vector2(0, -40)
        self.hp_images = import_folder('../mygame1/graphics/monster/monster_hp/')

    def import_assets(self):
        self.animations = {
            'up': [], 'down': [], 'left': [], 'right': [],
            'right_ack': [], 'left_ack': [], 'up_ack': [], 'down_ack': [],
            'up_d':[],'down_d':[],'left_d':[],'right_d':[],
            'moster_ex':[]
        }
        
        #print(f"正在从路径加载资源: {self._filepath}")
        for animation in self.animations.keys():
            full_path = self._filepath + animation
            #print(f"尝试加载动画: {full_path}")
            frames = import_folder(full_path)
           
            self.animations[animation] = frames

    def update_state(self, dt):
        """更新状态机"""
        # 更新状态计时器
        self.state_timer = max(0, self.state_timer - dt)
        
        # 获取与玩家的距离
        target = self.player.shadow if (self.player.is_dashing and hasattr(self.player, 'shadow') and self.player.shadow) else self.player
        target_pos = pygame.math.Vector2(target.rect.center)
        monster_pos = pygame.math.Vector2(self.rect.center)
        distance = (target_pos - monster_pos).magnitude()
        
        # 状态转换逻辑
        if self.current_state == MonsterState.DYING:
            return
            
        if self.current_state == MonsterState.ATTACK:
            if self.state_timer <= 0:
                self.current_state = MonsterState.CHASE
                self.reset_attack_state()
            return
            
        # 检查是否可以攻击
        if distance <= self.attack_range-15 and self.state_timer <= 0:
            self.current_state = MonsterState.ATTACK
            self.state_timer = self.state_cooldowns[MonsterState.ATTACK]
            self.prepare_attack(target_pos - monster_pos)
        # 否则进入追击状态
        elif distance > self.attack_range:
            self.current_state = MonsterState.CHASE
            
    def prepare_attack(self, direction_to_target):
        """准备攻击状态"""
        dx, dy = direction_to_target.x, direction_to_target.y
        
        # 设置攻击动画方向
        if abs(dx) > abs(dy):
            self.status = 'right_ack' if dx > 0 else 'left_ack'
        else:
            self.status = 'down_ack' if dy > 0 else 'up_ack'
            
        self.can_deal_damage = False
        self.damage_dealt = False
        self.speed = 0
        self.frame_index = 0
        
        if self.debug:
            print(f"准备攻击 - 状态: {self.status}")
            
    def update(self, dt):
        """主更新循环"""
        # 新状态机
        self.update_state(dt)
        
        # 根据当前状态执行相应行为
        if self.current_state == MonsterState.DYING:
            return
            
        elif self.current_state == MonsterState.ATTACK:
            self.check_attack_damage()
            
        elif self.current_state == MonsterState.CHASE:
            self.update_direction()
            self.move(dt)
            
        # 更新动画
        self.animate(dt)
        
    def take_damage(self, amount):
        """受到伤害时的处理"""
        if self.current_state == MonsterState.DYING:
            return
            
        self.health -= amount
        
        if self.health <= 0:
            self.current_state = MonsterState.DYING
            current_direction = self.status.split('_')[0]
            death_status = f'{current_direction}_d'
            death_frames = self.animations[death_status]
            
            if death_frames:
                DeathAnimation(self.pos, death_frames, self.level)
                # 只有设置了掉落经验值的怪物才会生成经验球
                if self.drops_experience:
                    Experience(self.pos, [self.level], self.player)
                # 增加玩家分数
                self.player.add_score(self.score_value)
            self.kill()

    def draw_hp_bar(self, surface, offset):
        """绘制血条"""
        if self.current_state == MonsterState.DYING or not self.hp_images or not self.max_health:
            return
            
        # 计算血条位置（考虑相机偏移）
        hp_pos = self.rect.midtop + self.hp_bar_offset - offset
        
        # 计算当前血量对应的图片索引
        health_ratio = self.health / self.max_health
        index = int((len(self.hp_images) - 1) * health_ratio)
        index = max(0, min(index, len(self.hp_images) - 1))
        
        # 绘制血条
        hp_image = self.hp_images[index]
        hp_rect = hp_image.get_rect(midtop=hp_pos)
        surface.blit(hp_image, hp_rect)

    def update_direction(self):
        # 确定目标(玩家或玩家的替身)
        target = self.player.shadow if (self.player.is_dashing and hasattr(self.player, 'shadow') and self.player.shadow) else self.player
        
        # 计算与目标的向量和距离（使用hitbox中心）
        target_pos = pygame.math.Vector2(target.hitbox.center)
        monster_pos = pygame.math.Vector2(self.hitbox.center)
        monster_to_target = target_pos - monster_pos
        distance = monster_to_target.magnitude()
        
        # 如果不在攻击状态，检查是否需要触发攻击
        if self.current_state != MonsterState.ATTACK:
            # 计算相对位置（使用hitbox中心）
            dx = target_pos.x - monster_pos.x
            dy = target_pos.y - monster_pos.y
            
            # 使用怪物自身的攻击范围
            attack_range = self.attack_range
            
            # 根据垂直方向调整攻击范围
            if abs(dy) > abs(dx):  # 主要是垂直方向的移动
                if dy < 0:  # 向上攻击
                    attack_range *= 1.2  # 向上攻击范围变为1.4倍
                elif dy > 0:  # 向下攻击
                    attack_range *= 0.1  # 向下攻击范围变为0.5倍
            
            # 检查是否在攻击范围内
            if distance <= attack_range:
                # 判断主要方向（水平/垂直）
                if abs(dx) > abs(dy):
                    # 水平方向攻击
                    self.status = 'right_ack' if dx > 0 else 'left_ack'
                else:
                    # 垂直方向攻击
                    self.status = 'down_ack' if dy > 0 else 'up_ack'
                
                if self.debug:
                    print(f"触发攻击 - 状态: {self.status}")
                    print(f"相对位置: dx={dx}, dy={dy}")
                    print(f"距离: {distance}, 攻击范围: {attack_range}")
                
                self.current_state = MonsterState.ATTACK
                self.state_timer = self.state_cooldowns[MonsterState.ATTACK]
                self.prepare_attack(monster_to_target)
                return
        
        # 不在攻击范围内或正在攻击时，更新移动方向
        if distance > 0 and self.current_state != MonsterState.ATTACK:
            self.direction = monster_to_target.normalize()
            # 更新移动状态
            if abs(monster_to_target.x) > abs(monster_to_target.y):
                self.status = 'right' if monster_to_target.x > 0 else 'left'
            else:
                self.status = 'down' if monster_to_target.y > 0 else 'up'

    def point_in_polygon(self, point, polygon):
        """检查点是否在多边形内部（射线法）"""
        x, y = point
        n = len(polygon)
        inside = False
        
        j = n - 1
        for i in range(n):
            if ((polygon[i][1] > y) != (polygon[j][1] > y) and
                (x < (polygon[j][0] - polygon[i][0]) * (y - polygon[i][1]) /
                 (polygon[j][1] - polygon[i][1]) + polygon[i][0])):
                inside = not inside
            j = i
        
        return inside

    def start_attack(self, direction_to_target):
        """开始攻击"""
        self.is_attacking = True
        self.can_deal_damage = False
        self.damage_dealt = False
        self.speed = 0
        self.frame_index = 0
        self.attack_direction = direction_to_target
        
        if self.debug:
            print(f"开攻击 - 状���: {self.status}")
            print(f"方向: x={direction_to_target.x}, y={direction_to_target.y}")

    def check_attack_damage(self):
        if self.damage_dealt:
            return

        # 检查是否在攻击帧窗口内
        current_frame = int(self.frame_index)
        self.can_deal_damage = self.attack_frame_window[0] <= current_frame <= self.attack_frame_window[1]
        
        if not self.can_deal_damage or self.damage_dealt:
            return
            
        # 设置攻击范围
        attack_range = self.attack_range * 2
        width_multiplier = 7
        center_x, center_y = self.hitbox.center
        
        # 根据攻击方设置攻击范围多边形
        direction = self.status.split('_')[0]
        points = []
        
        if direction == 'left':
            points = [
                (center_x, center_y - self.hitbox.height),
                (center_x, center_y + self.hitbox.height),
                (center_x - attack_range, center_y - (self.hitbox.height * width_multiplier)),
                (center_x - attack_range, center_y + (self.hitbox.height * width_multiplier))
            ]
        elif direction == 'right':
            points = [
                (center_x, center_y - self.hitbox.height),
                (center_x, center_y + self.hitbox.height),
                (center_x + attack_range, center_y - (self.hitbox.height * width_multiplier)),
                (center_x + attack_range, center_y + (self.hitbox.height * width_multiplier))
            ]
        elif direction == 'up':
            points = [
                (center_x - self.hitbox.width, center_y),
                (center_x + self.hitbox.width, center_y),
                (center_x - (self.hitbox.width * width_multiplier), center_y - attack_range),
                (center_x + (self.hitbox.width * width_multiplier), center_y - attack_range)
            ]
        else:  # down
            points = [
                (center_x - self.hitbox.width, center_y),
                (center_x + self.hitbox.width, center_y),
                (center_x - (self.hitbox.width * width_multiplier), center_y + attack_range),
                (center_x + (self.hitbox.width * width_multiplier), center_y + attack_range)
            ]
            
        # 检查玩家是否在攻击范围内
        target_pos = pygame.math.Vector2(self.player.hitbox.center)
        if self.point_in_polygon((target_pos.x, target_pos.y), points):
            if not self.player.is_invincible and not self.player.is_dashing:
                self.player.take_damage(self.attack_damage)
                self.damage_dealt = True

    def animate(self, dt):
        """处理动画"""
        current_animation = self.animations[self.status]
        if not current_animation:
            return
            
        # 更新帧索引
        animation_speed = 15 if self.current_state == MonsterState.DYING else 7
        self.frame_index += animation_speed * dt
        
        # 处理动画循环或结束
        if self.current_state == MonsterState.DYING:
            if int(self.frame_index) >= len(current_animation) - 1:
                self.kill()
                return
        else:
            if self.frame_index >= len(current_animation):
                self.frame_index = 0
                if self.current_state == MonsterState.ATTACK:
                    self.reset_attack_state()
        
        # 更新当前帧图像
        frame_index = min(int(self.frame_index), len(current_animation) - 1)
        self.image = current_animation[frame_index]
        self.rect = self.image.get_rect(center=self.hitbox.center)
        
    def reset_attack_state(self):
        """重置攻击状态"""
        self.is_attacking = False
        self.can_deal_damage = False
        self.damage_dealt = False
        self.speed = 100
        
        # 更新朝向状
        if self.direction:
            if abs(self.direction.x) > abs(self.direction.y):
                self.status = 'right' if self.direction.x > 0 else 'left'
            else:
                self.status = 'down' if self.direction.y > 0 else 'up'
                
    def move(self, dt):
        if self.current_state == MonsterState.ATTACK or not self.direction.magnitude() or not self.speed:
            return

        # 保存原始位置并计算新位置
        original_pos = pygame.math.Vector2(self.pos)
        self.pos += self.direction * self.speed * dt
        self.hitbox.center = round(self.pos.x), round(self.pos.y)
        
        # 处理碰撞
        self.handle_monster_collision(dt)
        if self.hitbox.colliderect(self.player.hitbox):
            self.pos = original_pos
            self.hitbox.center = round(self.pos.x), round(self.pos.y)
        
        self.rect.center = self.hitbox.center

    def handle_monster_collision(self, dt):
        if not self.groups():
            return
            
        # 获取所有其他怪物
        monsters = [sprite for sprite in self.groups()[0].sprites() 
                   if isinstance(sprite, BaseMonster) and sprite != self]
        
        for other in monsters:
            overlap = self.hitbox.clip(other.hitbox)
            if overlap.width > 0 and overlap.height > 0:
                # 计算最许重叠距离
                max_overlap = min(self.hitbox.width, self.hitbox.height) * 0.4
                current_overlap = max(overlap.width, overlap.height)
                
                if current_overlap > max_overlap:
                    # 计算推开方向和距离
                    push_direction = pygame.math.Vector2(
                        self.hitbox.centerx - other.hitbox.centerx,
                        self.hitbox.centery - other.hitbox.centery
                    ).normalize()
                    
                    push_distance = (current_overlap - max_overlap) / 2
                    self.pos += push_direction * push_distance
                    self.hitbox.center = round(self.pos.x), round(self.pos.y)

class DeathAnimation(pygame.sprite.Sprite):
    """死亡动画精灵：
    处理怪物死亡时的动画效果
    """
    def __init__(self, pos, animation_frames, groups):
        super().__init__(groups)
        
        self.frames = animation_frames
        self.frame_index = 0
        self.animation_speed = 0.05
        self.image = self.frames[self.frame_index]
        self.rect = self.image.get_rect()
        self.z = LAYERS['main']
        
        self.pos = pygame.math.Vector2(pos)
        self.rect.center = self.pos
        
    def animate(self, dt):
        self.frame_index += self.animation_speed
        if int(self.frame_index) >= len(self.frames):
            print("死亡动画播放完毕")
            self.kill()
            return
            
        # 更新图像
        frame_index = int(self.frame_index)
        self.image = self.frames[frame_index]
        self.rect.center = self.pos

    
    def update(self, dt):
        self.animate(dt)

class Experience(pygame.sprite.Sprite):
    """经验值球动画精灵"""
    def __init__(self, pos, groups, player):
        super().__init__(groups)
        self.player = player
        
        # 加载动画
        self.frames = import_folder('../mygame1/graphics/monster/monster_ex/')
        self.frame_index = 0
        self.animation_speed = 0.15
        
        # 设置精灵属性
        self.image = self.frames[self.frame_index]
        self.rect = self.image.get_rect()
        self.z = LAYERS['main']
        
        # 位置设置
        self.pos = pygame.math.Vector2(pos)
        self.rect.center = self.pos
        self.hitbox = self.rect.copy().inflate(-20, -20)
        
        # 检测范围
        self.collect_radius = 50
        
        # 延迟收集
        self.can_collect = False
        self.spawn_time = pygame.time.get_ticks()
        self.collect_delay = 1000  # 1秒延迟
        
    def update(self, dt):
        """更新经验值球状态"""
        # 检查是否可以收集
        current_time = pygame.time.get_ticks()
        if not self.can_collect and current_time - self.spawn_time >= self.collect_delay:
            self.can_collect = True
        
        # 只有在可以收集的状态下才检查玩家距离
        if self.can_collect:
            # 检查玩家是否在收集范围内
            player_pos = pygame.math.Vector2(self.player.hitbox.center)
            orb_pos = pygame.math.Vector2(self.hitbox.center)
            distance = (player_pos - orb_pos).magnitude()
            
            if distance <= self.collect_radius:
                # TODO: 在这里添加经验值收集逻辑
                self.player.add_exp(10)
                print(f"经验值增加1，当前经验值: {self.player.exp}")
                self.kill()
                return
            
        # 更新动画
        self.frame_index += self.animation_speed
        if self.frame_index >= len(self.frames):
            self.frame_index = 0
            
        self.image = self.frames[int(self.frame_index)]
        self.rect.center = self.pos

class Monster1(BaseMonster):
    """怪物1类型：
    - 血量较高 (30)
    - 伤害较低 (1)
    - 移动速度较慢 (80)
    - 攻击范围较大 (40)
    - 特性：血量只能是5的倍数
    - 掉落：经验值
    """
    def __init__(self, pos, group, player):
        self._filepath = '../mygame1/graphics/monster/monster1/'
        super().__init__(pos, group, player)
        
        # Monster1 特有属性
        self.max_health = 30
        self.health = self.max_health
        self.attack_damage = 1
        self.attack_range = 45
        self.speed = 80
        self.attack_frame_window = (3, 5)
        self.drops_experience = True  # Monster1 会掉落经验值
        self.score_value = 10  # Monster1 击杀得分
        
    def take_damage(self, amount):
        """处理受到伤害"""
        if self.current_state == MonsterState.DYING:
            return
            
        self.health -= amount
        self.health = (self.health // 5) * 5  # Monster1特有的血量取整
        
        if self.health <= 0:
            self.current_state = MonsterState.DYING
            current_direction = self.status.split('_')[0]
            death_status = f'{current_direction}_d'
            death_frames = self.animations[death_status]
            
            if death_frames:
                DeathAnimation(self.pos, death_frames, self.level)
                # 50%概率生成经验球
                if self.drops_experience and random.random() < 0.5:
                    Experience(self.pos, [self.level], self.player)
                # 增加玩家分数
                self.player.add_score(self.score_value)
            self.kill()

class Monster2(BaseMonster):
    """怪物2类型：
    - 血量较低 (6)
    - 伤害较高 (2)
    - 移动速度较快 (120)
    - 攻击范围较小 (30)
    - 掉落：50%概率掉落经验值
    """
    def __init__(self, pos, group, player):
        self._filepath = '../mygame1/graphics/monster/monster2/'
        super().__init__(pos, group, player)
        
        # Monster2 特有属性
        self.max_health = 6
        self.health = self.max_health
        self.attack_damage = 2
        self.attack_range = 35
        self.speed = 120
        self.attack_frame_window = (4, 7)
        self.drops_experience = True  # Monster2 也可以掉落经验值
        self.score_value = 10  # Monster2 击杀得分
        
    def take_damage(self, amount):
        """处理受到伤害"""
        if self.current_state == MonsterState.DYING:
            return
            
        self.health -= amount
        print(f"Monster2 受到 {amount} 点伤害，剩余命值: {self.health}")
        
        if self.health <= 0:
            self.current_state = MonsterState.DYING
            current_direction = self.status.split('_')[0]
            death_status = f'{current_direction}_d'
            death_frames = self.animations[death_status]
            
            if death_frames:
                DeathAnimation(self.pos, death_frames, self.level)
                # 50%概率生成经验球
                if self.drops_experience and random.random() < 0.5:
                    Experience(self.pos, [self.level], self.player)
                # 增加玩家分数
                self.player.add_score(self.score_value)
            self.kill()
